.. role:: raw-html-m2r(raw) :format: html .. _Int: UInt/SInt ========= Description ^^^^^^^^^^^ The ``UInt``/``SInt`` type corresponds to a vector of bits that can be used for signed/unsigned integer arithmetic. Declaration ^^^^^^^^^^^ The syntax to declare an integer is as follows: (everything between [] is optional) .. list-table:: :header-rows: 1 :widths: 5 10 2 * - Syntax - Description - Return * - | UInt[()] | SInt[()] - Create an unsigned/signed integer, bits count is inferred - | UInt | SInt * - | UInt(x bits) | SInt(x bits) - Create an unsigned/signed integer with x bits - | UInt | SInt * - | U(value: Int[,x bits]) | U(value: BigInt[,x bits]) | S(value: Int[,x bits]) | S(value: BigInt[,x bits]) - Create an unsigned/signed integer assigned with 'value' - | UInt | SInt * - | U"[[size']base]value" | S"[[size']base]value" - Create an unsigned/signed integer assigned with 'value' (Base : 'h', 'd', 'o', 'b') - | UInt | SInt * - | U([x bits,] :ref:`element `, ...) | S([x bits,] :ref:`element `, ...) - Create an unsigned integer assigned with the value specified by elements - | UInt | SInt .. code-block:: scala val myUInt = UInt(8 bits) myUInt := U(2,8 bits) myUInt := U(2) myUInt := U"0000_0101" // Base per default is binary => 5 myUInt := U"h1A" // Base could be x (base 16) // h (base 16) // d (base 10) // o (base 8) // b (base 2) myUInt := U"8'h1A" myUInt := 2 // You can use a Scala Int as a literal value val myBool := myUInt === U(7 -> true,(6 downto 0) -> false) val myBool := myUInt === U(myUInt.range -> true) // For assignment purposes, you can omit the U/S, which also allows the use of the [default -> ???] feature myUInt := (default -> true) // Assign myUInt with "11111111" myUInt := (myUInt.range -> true) // Assign myUInt with "11111111" myUInt := (7 -> true, default -> false) // Assign myUInt with "10000000" myUInt := ((4 downto 1) -> true, default -> false) // Assign myUInt with "00011110" Operators ^^^^^^^^^ The following operators are available for the ``UInt`` and ``SInt`` types: Logic ~~~~~ .. list-table:: :header-rows: 1 :widths: 2 4 2 * - Operator - Description - Return type * - x ^ y - Logical XOR - Bool * - ~x - Bitwise NOT - T(w(x) bits) * - x & y - Bitwise AND - T(max(w(x), w(y)) bits) * - x | y - Bitwise OR - T(max(w(x), w(y)) bits) * - x ^ y - Bitwise XOR - T(max(w(x), w(y)) bits) * - x.xorR - XOR all bits of x - Bool * - x.orR - OR all bits of x - Bool * - x.andR - AND all bits of x - Bool * - x \>\> y - Arithmetic shift right, y : Int - T(w(x) - y bits) * - x \>\> y - Arithmetic shift right, y : UInt - T(w(x) bits) * - x \<\< y - Arithmetic shift left, y : Int - T(w(x) + y bits) * - x \<\< y - Arithmetic shift left, y : UInt - T(w(x) + max(y) bits) * - x \|\>\> y - Logical shift right, y : Int/UInt - T(w(x) bits) * - x \|\<\< y - Logical shift left, y : Int/UInt - T(w(x) bits) * - x.rotateLeft(y) - Logical left rotation, y : UInt/Int - T(w(x) bits) * - x.rotateRight(y) - Logical right rotation, y : UInt/Int - T(w(x) bits) * - x.clearAll[()] - Clear all bits - * - x.setAll[()] - Set all bits - * - x.setAllTo(value : Boolean) - Set all bits to the given Boolean value - * - x.setAllTo(value : Bool) - Set all bits to the given Bool value - .. note:: ``x rotateLeft y`` and ``x rotateRight y`` are also valid syntax. .. note:: Notice the difference between ``x >> 2``:T(w(x)-2) and ``x >> U(2)``:T(w(x)). The difference is that in the first case 2 is an ``Int`` (which can be seen as an "elaboration integer"), and in the second case it is a hardware signal. .. code-block:: scala val a, b, c = SInt(32 bits) a := S(5) b := S(10) // Bitwise operators c := ~(a & b) // Inverse(a AND b) assert(c.getWidth == 32) // Shift val arithShift = UInt(8 bits) << 2 // shift left (resulting in 10 bits) val logicShift = UInt(8 bits) |<< 2 // shift left (resulting in 8 bits) assert(arithShift.getWidth == 10) assert(logicShift.getWidth == 8) // Rotation val rotated = UInt(8 bits) rotateLeft 3 // left bit rotation assert(rotated.getWidth == 8) // Set all bits of b to True when all bits of a are True when(a.andR) { b.setAll() } Arithmetic ~~~~~~~~~~ .. list-table:: :header-rows: 1 * - Operator - Description - Return * - x + y - Addition - T(max(w(x), w(y)) bits) * - x +^ y - Addition with carry - T(max(w(x), w(y)) + 1 bits) * - x +| y - Addition by sat carry bit - T(max(w(x), w(y)) bits) * - x - y - Subtraction - T(max(w(x), w(y)) bits) * - x -^ y - Subtraction with carry - T(max(w(x), w(y)) + 1 bits) * - x -| y - Subtraction by sat carry bit - T(max(w(x), w(y)) bits) * - x * y - Multiplication - T(w(x) + w(y)) bits) * - x / y - Division - T(w(x) bits) * - x % y - Modulo - T(min(w(x), w(y)) bits) .. code-block:: scala val a, b, c = UInt(8 bits) a := U"xf0" b := U"x0f" c := a + b assert(c === U"8'xff") val d = a +^ b assert(d === U"9'x0ff") val e = a +| U"8'x20" assert(e === U"8'xff") .. note:: Notice how simulation assertions are made here (with ``===``), as opposed to elaboration assertions in the previous example (with ``==``). Comparison ~~~~~~~~~~ .. list-table:: :header-rows: 1 * - Operator - Description - Return type * - x === y - Equality - Bool * - x =/= y - Inequality - Bool * - x > y - Greater than - Bool * - x >= y - Greater than or equal - Bool * - x < y - Less than - Bool * - x <= y - Less than or equal - Bool .. code-block:: scala val a = U(5, 8 bits) val b = U(10, 8 bits) val c = UInt(2 bits) when (a > b) { c := U"10" } elsewhen (a =/= b) { c := U"01" } elsewhen (a === U(0)) { c.setAll() } otherwise { c.clearAll() } Type cast ~~~~~~~~~ .. list-table:: :header-rows: 1 * - Operator - Description - Return * - x.asBits - Binary cast to Bits - Bits(w(x) bits) * - x.asUInt - Binary cast to UInt - UInt(w(x) bits) * - x.asSInt - Binary cast to SInt - SInt(w(x) bits) * - x.asBools - Cast into a array of Bool - Vec(Bool, w(x)) * - S(x: T) - Cast a Data into a SInt - SInt(w(x) bits) * - U(x: T) - Cast a Data into an UInt - UInt(w(x) bits) * - x.intoSInt - Convert to SInt expanding sign bit - SInt(w(x) + 1 bits) To cast a ``Bool``, a ``Bits``, or an ``SInt`` into a ``UInt``, you can use ``U(something)``. To cast things into an ``SInt``, you can use ``S(something)``. .. code-block:: scala // Cast an SInt to Bits val myBits = mySInt.asBits // Create a Vector of Bool val myVec = myUInt.asBools // Cast a Bits to SInt val mySInt = S(myBits) Bit extraction ~~~~~~~~~~~~~~ .. list-table:: :header-rows: 1 :widths: 2 6 2 * - Operator - Description - Return * - x(y) - Readbit, y : Int/UInt - Bool * - x(offset, width) - Read bitfield, offset: UInt, width: Int - T(width bits) * - x(\ :ref:`range `\ ) - Read a range of bits. Ex : myBits(4 downto 2) - T(range bits) * - x(y) := z - Assign bits, y : Int/UInt - Bool * - x(offset, width) := z - Assign bitfield, offset: UInt, width: Int - T(width bits) * - x(\ :ref:`range `\ ) := z - Assign a range of bit. Ex : myBits(4 downto 2) := U"010" - T(range bits) .. code-block:: scala // get the bit at index 4 val myBool = myUInt(4) // assign bit 1 to True mySInt(1) := True // Range val myUInt_8bits = myUInt_16bits(7 downto 0) val myUInt_7bits = myUInt_16bits(0 to 6) val myUInt_6bits = myUInt_16Bits(0 until 6) mySInt_8bits(3 downto 0) := mySInt_4bits Misc ~~~~ .. list-table:: :header-rows: 1 :widths: 2 5 1 * - Operator - Description - Return * - x.getWidth - Return bitcount - Int * - x.msb - Return the most significant bit - Bool * - x.lsb - Return the least significant bit - Bool * - x.range - Return the range (x.high downto 0) - Range * - x.high - Return the upper bound of the type x - Int * - x ## y - Concatenate, x->high, y->low - Bits(w(x) + w(y) bits) * - x @@ y - Concatenate x:T with y:Bool/SInt/UInt - T(w(x) + w(y) bits) * - x.subdivideIn(y slices) - Subdivide x into y slices, y: Int - Vec(T, y) * - x.subdivideIn(y bits) - Subdivide x into multiple slices of y bits, y: Int - Vec(T, w(x)/y) * - x.resize(y) - | Return a resized copy of x, if enlarged, it is filled with zero | for UInt or filled with the sign for SInt, y: Int - T(y bits) * - x.resized - | Return a version of x which is allowed to be automatically | resized where needed - T(w(x) bits) * - myUInt.twoComplement(en: Bool) - Use the two's complement to transform an UInt into an SInt - SInt(w(myUInt) + 1, bits) * - mySInt.abs - Return the absolute value as a UInt value - UInt(w(mySInt), bits) * - mySInt.abs(en: Bool) - Return the absolute value as a UInt value when en is True - UInt(w(mySInt), bits) * - mySInt.sign - Return most significant bit - Bool * - x.expand - Return x with 1 bit expand - T(w(x)+1 bits) * - mySInt.absWithSym - Return the absolute value of the UInt value with symmetric, shrink 1 bit - UInt(w(mySInt) - 1 bits) .. code-block:: scala myBool := mySInt.lsb // equivalent to mySInt(0) // Concatenation val mySInt = mySInt_1 @@ mySInt_1 @@ myBool val myBits = mySInt_1 ## mySInt_1 ## myBool // Subdivide val sel = UInt(2 bits) val mySIntWord = mySInt_128bits.subdivideIn(32 bits)(sel) // sel = 0 => mySIntWord = mySInt_128bits(127 downto 96) // sel = 1 => mySIntWord = mySInt_128bits( 95 downto 64) // sel = 2 => mySIntWord = mySInt_128bits( 63 downto 32) // sel = 3 => mySIntWord = mySInt_128bits( 31 downto 0) // If you want to access in reverse order you can do: val myVector = mySInt_128bits.subdivideIn(32 bits).reverse val mySIntWord = myVector(sel) // Resize myUInt_32bits := U"32'x112233344" myUInt_8bits := myUInt_32bits.resized // automatic resize (myUInt_8bits = 0x44) myUInt_8bits := myUInt_32bits.resize(8) // resize to 8 bits (myUInt_8bits = 0x44) // Two's complement mySInt := myUInt.twoComplement(myBool) // Absolute value mySInt_abs := mySInt.abs FixPoint operations ^^^^^^^^^^^^^^^^^^^ For fixpoint, we can divide it into two parts: - Lower bit operations (rounding methods) - High bit operations (saturation operations) Lower bit operations ~~~~~~~~~~~~~~~~~~~~ .. image:: /asset/image/fixpoint/lowerBitOperation.png About Rounding: https://en.wikipedia.org/wiki/Rounding ================ ================= ============= ======================== ====================== =========== SpinalHDL-Name Wikipedia-Name API Mathematic Algorithm return(align=false) Supported ================ ================= ============= ======================== ====================== =========== FLOOR RoundDown floor floor(x) w(x)-n bits Yes FLOORTOZERO RoundToZero floorToZero sign*floor(abs(x)) w(x)-n bits Yes CEIL RoundUp ceil ceil(x) w(x)-n+1 bits Yes CEILTOINF RoundToInf ceilToInf sign*ceil(abs(x)) w(x)-n+1 bits Yes ROUNDUP RoundHalfUp roundUp floor(x+0.5) w(x)-n+1 bits Yes ROUNDDOWN RoundHalfDown roundDown ceil(x-0.5) w(x)-n+1 bits Yes ROUNDTOZERO RoundHalfToZero roundToZero sign*ceil(abs(x)-0.5) w(x)-n+1 bits Yes ROUNDTOINF RoundHalfToInf roundToInf sign*floor(abs(x)+0.5) w(x)-n+1 bits Yes ROUNDTOEVEN RoundHalfToEven roundToEven No ROUNDTOODD RoundHalfToOdd roundToOdd No ================ ================= ============= ======================== ====================== =========== .. note:: The **RoundToEven** and **RoundToOdd** modes are very special, and are used in some big data statistical fields with high accuracy concerns, SpinalHDL doesn't support them yet. You will find `ROUNDUP`, `ROUNDDOWN`, `ROUNDTOZERO`, `ROUNDTOINF`, `ROUNDTOEVEN`, `ROUNTOODD` are very close in behavior, `ROUNDTOINF` is the most common. The behavior of rounding in different programming languages may be different. ====================== =================== ========================================================= ==================== Programming language default-RoundType Example comments ====================== =================== ========================================================= ==================== Matlab ROUNDTOINF round(1.5)=2,round(2.5)=3;round(-1.5)=-2,round(-2.5)=-3 round to ±Infinity python2 ROUNDTOINF round(1.5)=2,round(2.5)=3;round(-1.5)=-2,round(-2.5)=-3 round to ±Infinity python3 ROUNDTOEVEN round(1.5)=round(2.5)=2; round(-1.5)=round(-2.5)=-2 close to Even Scala.math ROUNDTOUP round(1.5)=2,round(2.5)=3;round(-1.5)=-1,round(-2.5)=-2 always to +Infinity SpinalHDL ROUNDTOINF round(1.5)=2,round(2.5)=3;round(-1.5)=-2,round(-2.5)=-3 round to ±Infinity ====================== =================== ========================================================= ==================== .. note:: In SpinalHDL `ROUNDTOINF` is the default RoundType (``round = roundToInf``) .. code-block:: scala val A = SInt(16 bits) val B = A.roundToInf(6 bits) // default 'align = false' with carry, got 11 bit val B = A.roundToInf(6 bits, align = true) // sat 1 carry bit, got 10 bit val B = A.floor(6 bits) // return 10 bit val B = A.floorToZero(6 bits) // return 10 bit val B = A.ceil(6 bits) // ceil with carry so return 11 bit val B = A.ceil(6 bits, align = true) // ceil with carry then sat 1 bit return 10 bit val B = A.ceilToInf(6 bits) val B = A.roundUp(6 bits) val B = A.roundDown(6 bits) val B = A.roundToInf(6 bits) val B = A.roundToZero(6 bits) val B = A.round(6 bits) // SpinalHDL uses roundToInf as the default rounding mode val B0 = A.roundToInf(6 bits, align = true) // ---+ // |--> equal val B1 = A.roundToInf(6 bits, align = false).sat(1) // ---+ .. note:: Only ``floor`` and ``floorToZero`` work without the ``align`` option; they do not need a carry bit. Other rounding operations default to using a carry bit. **round Api** ============= =========== ============================ ===================== ==================== API UInt/SInt description Return(align=false) Return(align=true) ============= =========== ============================ ===================== ==================== floor Both w(x)-n bits w(x)-n bits floorToZero SInt equal to floor in UInt w(x)-n bits w(x)-n bits ceil Both w(x)-n+1 bits w(x)-n bits ceilToInf SInt equal to ceil in UInt w(x)-n+1 bits w(x)-n bits roundUp Both simple for HW w(x)-n+1 bits w(x)-n bits roundDown Both w(x)-n+1 bits w(x)-n bits roundToInf SInt most Common w(x)-n+1 bits w(x)-n bits roundToZero SInt equal to roundDown in UInt w(x)-n+1 bits w(x)-n bits round Both SpinalHDL chose roundToInf w(x)-n+1 bits w(x)-n bits ============= =========== ============================ ===================== ==================== .. note:: Although ``roundToInf`` is very common, ``roundUp`` has the least cost and good timing, with almost no performance loss. As a result, ``roundUp`` is strongly recommended for production use. High bit operations ~~~~~~~~~~~~~~~~~~~ .. image:: /asset/image/fixpoint/highBitOperation.png ========== ============ ====================================== ======================================= function Operation Positive-Op Negative-Op ========== ============ ====================================== ======================================= sat Saturation when(Top[w-1, w-n].orR) set maxValue When(Top[w-1, w-n].andR) set minValue trim Discard N/A N/A symmetry Symmetric N/A minValue = -maxValue ========== ============ ====================================== ======================================= Symmetric is only valid for ``SInt``. .. code-block:: scala val A = SInt(8 bits) val B = A.sat(3 bits) // return 5 bits with saturated highest 3 bits val B = A.sat(3) // equal to sat(3 bits) val B = A.trim(3 bits) // return 5 bits with the highest 3 bits discarded val B = A.trim(3 bits) // return 5 bits with the highest 3 bits discarded val C = A.symmetry // return 8 bits and symmetry as (-128~127 to -127~127) val C = A.sat(3).symmetry // return 5 bits and symmetry as (-16~15 to -15~15) fixTo function ~~~~~~~~~~~~~~ Two ways are provided in ``UInt``/``SInt`` to do fixpoint: .. image:: /asset/image/fixpoint/fixPoint.png ``fixTo`` is strongly recommended in your RTL work, you don't need to handle carry bit alignment and bit width calculations manually like **Way1** in the above diagram. Factory Fix function with Auto Saturation: ===================================== ===================== =================== Function Description Return ===================================== ===================== =================== fixTo(section, roundType, symmetric) Factory FixFunction section.size bits ===================================== ===================== =================== .. code-block:: scala val A = SInt(16 bits) val B = A.fixTo(10 downto 3) // default RoundType.ROUNDTOINF, sym = false val B = A.fixTo( 8 downto 0, RoundType.ROUNDUP) val B = A.fixTo( 9 downto 3, RoundType.CEIL, sym = false) val B = A.fixTo(16 downto 1, RoundType.ROUNDTOINF, sym = true ) val B = A.fixTo(10 downto 3, RoundType.FLOOR) // floor 3 bit, sat 5 bit @ highest val B = A.fixTo(20 downto 3, RoundType.FLOOR) // floor 3 bit, expand 2 bit @ highest